package com.shortlink.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shortlink.admin.config.AdminConfiguration;
import com.shortlink.admin.dao.entity.GroupDO;
import com.shortlink.admin.dao.mapper.GroupMapper;
import com.shortlink.admin.dto.req.group.GroupInsertReqDTO;
import com.shortlink.admin.dto.req.group.GroupSortReqDTO;
import com.shortlink.admin.dto.req.group.GroupUpdateReqDTO;
import com.shortlink.admin.dto.resp.group.GroupRespDTO;
import com.shortlink.admin.service.GroupService;
import com.shortlink.admin.service.ShortLinkService;
import com.shortlink.common.exception.ClientException;
import com.shortlink.common.user.UserContext;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.shortlink.common.constant.RedisKeyConstant.GROUP_ID_GENERATOR_KEY;

/**
 * 短链接分组接口实现层
 *
 * @author wp
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Setter
public class GroupServiceImpl extends ServiceImpl<GroupMapper, GroupDO> implements GroupService {
    private final RedissonClient redissonClient;
    private final AdminConfiguration adminConfiguration;
    @Resource
    @Lazy
    private ShortLinkService shortLinkService;

    @Override
    public void saveGroup(GroupInsertReqDTO groupInsert) {
        saveGroup(UserContext.getUserId(), groupInsert);
    }

    @Override
    public void saveGroup(Long userId, GroupInsertReqDTO groupInsert) {
        if (ObjectUtil.isEmpty(userId)) {
            log.info(String.format("userId(%s) 不能为空", userId));
            throw new ClientException("参数错误");
        }

        String groupName = groupInsert.getGroupName();
        if (ObjectUtil.isEmpty(groupName)) {
            log.info("分组名为空");
            throw new ClientException("参数错误");
        }
        List<GroupDO> groupList = lambdaQuery()
                .eq(GroupDO::getUserId, userId)
                .eq(GroupDO::getDelFlag, GroupDO.DEL_FLAG_FAIL)
                .list();
        if (CollUtil.isNotEmpty(groupList)) {
            Integer groupMaxNum = adminConfiguration.getGroupMaxNum();
            if (groupList.size() >= groupMaxNum) {
                throw new ClientException(String.format("已超出最大分组数：%d", groupMaxNum));
            }
        }

        for (GroupDO group : groupList) {
            if (group.getName().equals(groupName)) {
                throw new ClientException("分组名重复");
            }
        }

        Long id = redissonClient.getIdGenerator(GROUP_ID_GENERATOR_KEY).nextId();
        GroupDO groupDO = GroupDO.builder()
                .id(id)
                .sortOrder(id.intValue())
                .userId(userId)
                .name(groupName)
                .build();
        baseMapper.insert(groupDO);
    }

    @Override
    public List<GroupRespDTO> listGroup() {
        List<GroupDO> groupDOList = lambdaQuery()
                .eq(GroupDO::getDelFlag, GroupDO.DEL_FLAG_FAIL)
                .eq(GroupDO::getUserId, UserContext.getUserId())
                .orderByAsc(GroupDO::getSortOrder)
                .orderByDesc(GroupDO::getUpdateTime)
                .list();
        if (ObjectUtil.isEmpty(groupDOList)) {
            return new ArrayList<>();
        }
        Map<Long, Integer> shortLinkCounts = shortLinkService.listGroupShortLinkCount(
                groupDOList.stream().map(GroupDO::getId).collect(Collectors.toList()));
        List<GroupRespDTO> shortLinkGroupRespDTOList = BeanUtil.copyToList(groupDOList, GroupRespDTO.class);
        shortLinkGroupRespDTOList.forEach(each -> each.setShortLinkCount(shortLinkCounts.get(each.getId())));
        return shortLinkGroupRespDTOList;
    }

    @Override
    public void updateGroup(GroupUpdateReqDTO groupUpdate) {
        Long gid = groupUpdate.getGid();
        String groupName = groupUpdate.getGroupName();
        if (!ObjectUtil.isAllNotEmpty(gid, groupName)) {
            log.info(String.format("gid(%s) groupName(%s)不能为空", gid, groupName));
            throw new ClientException("参数错误");
        }
        boolean succeed = lambdaUpdate()
                .eq(GroupDO::getUserId, UserContext.getUserId())
                .eq(GroupDO::getId, gid)
                .eq(GroupDO::getDelFlag, GroupDO.DEL_FLAG_FAIL)
                .set(GroupDO::getName, groupName)
                .update();
        if (!succeed) {
            throw new ClientException("分组更新失败（分组不存在）");
        }
    }

    @Override
    public void deleteGroup(Long gid) {
        boolean succeed = lambdaUpdate()
                .eq(GroupDO::getUserId, UserContext.getUserId())
                .eq(GroupDO::getId, gid)
                .eq(GroupDO::getDelFlag, GroupDO.DEL_FLAG_FAIL)
                .set(GroupDO::getDelFlag, GroupDO.DEL_FLAG_SUCCESS)
                .update();
        if (!succeed) {
            throw new ClientException("分组删除失败（分组不存在）");
        }
    }

    @Transactional
    @Override
    public void sortGroup(GroupSortReqDTO groupSortReq) {
        Long gid1 = groupSortReq.getGid1();
        Long gid2 = groupSortReq.getGid2();
        if (!ObjectUtil.isAllNotEmpty(gid1, gid2)) {
            log.info(String.format("gid1(%s) gid2(%s)不能为空", gid1, gid2));
            throw new ClientException("参数错误");
        } else if (gid1.equals(gid2)) {
            log.info(String.format("gid1(%s) gid2(%s)相同", gid1, gid2));
            throw new ClientException("参数错误");
        } else {
            Integer sortOrder1 = groupSortReq.getSortOrder1();
            Integer sortOrder2 = groupSortReq.getSortOrder2();
            boolean succeed1 = lambdaUpdate()
                    .eq(GroupDO::getUserId, UserContext.getUserId())
                    .eq(GroupDO::getId, gid1)
                    .eq(GroupDO::getDelFlag, GroupDO.DEL_FLAG_FAIL)
                    .eq(GroupDO::getSortOrder, sortOrder1)
                    .set(GroupDO::getSortOrder, sortOrder2)
                    .update();
            boolean succeed2 = lambdaUpdate()
                    .eq(GroupDO::getUserId, UserContext.getUserId())
                    .eq(GroupDO::getId, gid2)
                    .eq(GroupDO::getSortOrder, sortOrder2)
                    .eq(GroupDO::getDelFlag, GroupDO.DEL_FLAG_FAIL)
                    .set(GroupDO::getSortOrder, sortOrder1)
                    .update();
            if (!succeed1 || !succeed2) {
                throw new ClientException("排序用户分组不存在");
            }
        }
    }

    /**
     * 获取分组名
     */
    @Override
    public String getGroupNameById(Long gid) {
        GroupDO group = lambdaQuery()
                .eq(GroupDO::getId, gid)
                .eq(GroupDO::getDelFlag, GroupDO.DEL_FLAG_FAIL)
                .select(GroupDO::getName)
                .one();
        if (ObjectUtil.isEmpty(group)) {
            return null;
        }
        return group.getName();
    }
}
